package com.sun.sangeng.stream;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class StreamDemo {

    public static void main(String[] args) {

        //test01();
        //test02();
        //test03();

        // Stream流的中间操作
        //test04();   // 中间操作之filter [可以对流中的元素进行条件过滤，符合过滤条件的才能继续留在流中。]
        test05();   // 中间操作之map [可以把对流中的元素进行计算或转换。]
        //test06();   // 中间操作之distinct [可以去除流中的重复元素。]
        //test07();   // 中间操作之sorted [可以对流中的元素进行排序。]
        //test08();   // 中间操作之limit [可以设置流的最大长度，超出的部分将被抛弃。]
        //test09();   // 中间操作之skip [跳过流中的前n个元素，返回剩下的元素]
        //test10_1(); // 中间操作之flatMap [map只能把一个对象转换成另一个对象来作为流中的元素。而flatMap可以把一个对象转换成多个对象作为流中的元素。]
        //test10_2();

        // Stream流的终结操作
        //test11();   // 终结操作之foreEach [对流中的元素进行遍历操作，我们通过传入的参数去指定对遍历到的元素进行什么具体操作。]
        //test12();   // 终结操作之count [可以用来获取当前流中元素的个数。]
        //test13();   // 终结操作之max&min [可以用来或者流中的最值。]
        //test14();   // 终结操作之collect[把当前流转换成一个集合。]

        // Stream流的终结操作-查找与匹配
        //test15();    // 终结操作之anyMatch[可以用来判断是否有任意符合匹配条件的元素，结果为boolean类型。]
        //test16();    // 终结操作之allMatch[可以用来判断是否都符合匹配条件，结果为boolean类型。如果都符合结果为true，否则结果为false。]
        //test17();    // 终结操作之noneMatch[可以判断流中的元素是否都不符合匹配条件。如果都不符合结果为true，否则结果为false]
        //test18();    // 终结操作之findAny[获取流中的任意一个元素。该方法没有办法保证获取的一定是流中的第一个元素。]
        //test19();    // 终结操作之findFirst[获取流中的第一个元素。]

        // Stream流的终结操作-reduce（缩减操作）
        //test20();    // 终结操作之reduce归并[对流中的数据按照你指定的计算方式计算出一个结果。（缩减操作）reduce的作用是把stream中的元素给组合起来，我们可以传入一个初始值，它会按照我们的计算方式依次拿流中的元素和初始化值进行计算，计算结果再和后面的元素计算。]
    }


    private static void test20() {
        // (两个参数的reduce方法)使用reduce求所有作者年龄的和
        Integer sum = getAuthors().stream()
                .map(author -> author.getAge())
                .distinct()
                .reduce(0, (result, element) -> result + element);
        System.out.println("sum = " + sum);

        // (两个参数的reduce方法)使用reduce求所有作者中年龄的最大值
        Integer maxAge = getAuthors().stream()
                .map(author -> author.getAge())
                .reduce(Integer.MIN_VALUE, (result, element) -> result < element ? element : result);
        System.out.println("maxAge = " + maxAge);
        
        // (两个参数的reduce方法)使用reduce求所有作者中年龄的最小值
        Integer minAge = getAuthors().stream()
                .map(author -> author.getAge())
                .reduce(Integer.MAX_VALUE, (result, element) -> result > element ? element : result);
        System.out.println("minAge = " + minAge);
        
        // (一个参数的reduce方法) 使用reduce求所有作者中年龄的最小值
        Optional<Integer> minAge1 = getAuthors().stream()
                .map(author -> author.getAge())
                .reduce((result, element) -> result > element ? element : result);
        minAge1.ifPresent(integer -> System.out.println(integer));
        System.out.println("minAge1 = " + minAge1.get());
    }

    // 获取一个年龄最小的作家，并输出他的姓名。
    private static void test19() {
        Optional<Author> first = getAuthors().stream().sorted((v1, v2) -> v1.getAge() - v2.getAge()).findFirst();
        first.ifPresent(author -> System.out.println(author.getName()));
    }

    // 获取任意一个年龄大于18的作家，如果存在就输出他的名字
    private static void test18() {
        Optional<Author> any = getAuthors().stream().filter(author -> author.getAge() > 18).findAny();
        if (any.isPresent()) {
            System.out.println(any.get().getName());
        }

        any.ifPresent(author -> System.out.println(author.getName()));
    }

    // 判断作家是否都没有超过100岁的。
    private static void test17() {
        boolean b = getAuthors().stream().noneMatch(author -> author.getAge() >= 100);
        System.out.println(b);
    }

    // 判断是否所有的作家都是成年人
    private static void test16() {
        boolean b = getAuthors().stream()
                .allMatch(author -> author.getAge() > 18);
        System.out.println(b);
    }

    // 判断是否有年龄在29以上的作家
    private static void test15() {
        List<Author> authors = getAuthors();
        boolean flag = authors.stream()
                .anyMatch(author -> author.getAge() > 29);
        System.out.println(flag);
    }

    private static void test14() {
        List<Author> authors = getAuthors();

        // 获取一个存放所有作者名字的List集合。
        List<String> collectName = authors.stream()
                .map(author -> author.getName())
                .distinct()
                .collect(Collectors.toList());
        collectName.forEach(System.out::println);

        // 获取一个所有书名的Set集合。
        Set<String> collectBookName = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getName())
                .collect(Collectors.toSet());
        collectBookName.forEach(System.out::println);

        // 获取一个Map集合，map的key为作者名，value为List<Book>
        Map<String, List<Book>> collect = authors.stream()
                .distinct()
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
        collect.forEach((v1, v2) -> System.out.println(v1 + ":" + v2));
    }

    // 分别获取这些作家的所出书籍的最高分和最低分并打印。
    private static void test13() {

        List<Author> authors = getAuthors();

        Optional<Integer> maxScore = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .max((score1, score2) -> score1 - score2);
        System.out.println(maxScore.get());

        Optional<Integer> minScore = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .min(Comparator.comparingInt(score -> score));
        System.out.println(minScore.get());

        //authors.stream()
        //        .flatMap(author -> author.getBooks().stream())
        //        .distinct()
        //        .sorted((b1,b2) -> b2.getScore()-b1.getScore())
        //        .limit(1)
        //        .forEach(book -> System.out.println(book.getScore()));

    }

    // 打印这些作家的所出书籍的数目，注意删除重复元素。
    private static void test12() {
        List<Author> authors = getAuthors();

        long countBook = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .count();
        System.out.println(countBook);
    }

    // 输出所有作家的名字
    private static void test11() {
        List<Author> authors = getAuthors();

        //authors.stream().distinct().forEach(author -> System.out.println(author.getName()));
        authors.stream().map(author -> author.getName()).distinct().forEach(name -> System.out.println(name));

    }

    // 打印现有数据的所有分类。要求对分类进行去重。不能出现这种格式：哲学,爱情
    private static void test10_2() {
        List<Author> authors = getAuthors();
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .flatMap(book -> Arrays.stream(book.getCategory().split("，")))
                .distinct()
                .forEach(category -> System.out.println(category));
    }

    //打印所有书籍的名字。要求对重复的元素进行去重。
    private static void test10_1() {
        List<Author> authors = getAuthors();

        //Stream<Author> stream = authors.stream();
        //Stream<Book> bookStream = stream.flatMap(author -> author.getBooks().stream());
        //Stream<Book> distinct = bookStream.distinct();
        //distinct.forEach(book -> System.out.println(book.getName()));

        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .forEach(book -> System.out.println(book.getName()));

        //authors.stream()
        //        .flatMap(new Function<Author, Stream<Book>>() {
        //            @Override
        //            public Stream<Book> apply(Author author) {
        //                return author.getBooks().stream();
        //            }
        //        })
        //        .distinct()
        //        .forEach(new Consumer<Book>() {
        //            @Override
        //            public void accept(Book book) {
        //                System.out.println(book.getName());
        //            }
        //        });
    }

    // 打印除了年龄最大的作家外的其他作家，要求不能有重复元素，并且按照年龄降序排序。
    private static void test09() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted((v1, v2) -> v2.getAge() - v1.getAge())
                .skip(1)
                .forEach(author -> System.out.println(author));
    }

    // 对流中的元素按照年龄进行降序排序，并且要求不能有重复的元素,然后打印其中年龄最大的两个作家的姓名。
    private static void test08() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted((v1, v2) -> v2.getAge() - v1.getAge())
                .limit(2)
                .forEach(author -> System.out.println(author.getName()));

    }

    // 对流中的元素按照年龄进行降序排序，并且要求不能有重复的元素。
    private static void test07() {
        List<Author> authors = getAuthors();

        //authors.stream()
        //        .distinct()
        //        .sorted()
        //        .forEach(author -> System.out.println(author.getAge()));
        //                         

        //authors.stream()
        //        .distinct()
        //        .sorted(new MyComparator())
        //        .forEach(author -> System.out.println(author.getAge()));

        authors.stream()
                .distinct()
                .sorted((o1, o2) -> o1.getAge() - o2.getAge())
                .forEach(author -> System.out.println(author.getAge()));
    }

    // 打印所有作家的姓名，并且要求其中不能有重复元素。
    private static void test06() {
        List<Author> authors = getAuthors();
        authors.stream().distinct().forEach(author -> System.out.println(author.getName()));
    }

    // 打印所有作家的姓名
    private static void test05() {
        List<Author> authors = getAuthors();

        //authors.stream().distinct().forEach(author -> System.out.println(author.getName()));

        //authors.stream().
        //        map(author -> author.getName())
        //        .forEach(s -> System.out.println(s));

        authors.stream()
                .map(Author::getAge)
                .map(age -> age + 10)
                .filter(age -> age>18)
                .map(age -> age + 2)
                .forEach(System.out::println);

        // 使用maptToInt优化基本类型和基本数据类型包装类的自动装箱和拆箱操作，达到节约时间的目的(先使用匿名内部类)
        List<Author> authors1 = getAuthors();
        authors1.stream()
                .mapToInt(new ToIntFunction<Author>() {
                    @Override
                    public int applyAsInt(Author value) {
                        return value.getAge();
                    }
                }).map(new IntUnaryOperator() {
                    @Override
                    public int applyAsInt(int operand) {
                        return operand+10;
                    }
                }).filter(new IntPredicate() {
                    @Override
                    public boolean test(int value) {
                        return value > 18;
                    }
                }).map(new IntUnaryOperator() {
                    @Override
                    public int applyAsInt(int operand) {
                        return operand + 2;
                    }
                }).forEach(new IntConsumer() {
                    @Override
                    public void accept(int value) {
                        System.out.println("value = " + value);
                    }
                });

        // 使用maptToInt优化基本类型和基本数据类型包装类的自动装箱和拆箱操作，达到节约时间的目的(使用 lambda 和方法引用的方式替换上面匿名内部类的写法)
        List<Author> authors2 = getAuthors();
        authors2.stream()
                .mapToInt(Author::getAge)
                .map(age -> age + 10)
                .filter(age -> age>18)
                .map(age -> age+2)
                .forEach(System.out::println);
    }

    //打印所有姓名长度大于1的作家的姓名
    private static void test04() {
        List<Author> authors = getAuthors();
        authors.stream().distinct().filter(author -> author.getName().length() > 1).forEach(author -> System.out.println(author.getName()));
    }

    // map集合转换成Stream流
    private static void test03() {
        Map<String, Integer> map = new HashMap<>();
        map.put("蜡笔小新", 19);
        map.put("黑子", 17);
        map.put("日向翔阳", 16);

        Set<Map.Entry<String, Integer>> setEntries = map.entrySet();
        Stream<Map.Entry<String, Integer>> stream = setEntries.stream();
        //stream.filter(var -> var.getValue()>16).forEach(var -> System.out.println(var));

        stream.filter(stringIntegerEntry -> stringIntegerEntry.getValue() > 16).
                forEach(stringIntegerEntry -> System.out.println(stringIntegerEntry.getKey() + ":" + stringIntegerEntry.getValue()));
    }

    // 数组转换成Stream流
    private static void test02() {
        Integer[] arr = {1, 2, 3, 4, 5};
        Stream<Integer> integerStream = Arrays.stream(arr);
        integerStream.distinct().filter(integer -> integer > 3).forEach(System.out::println);

        Stream<Integer> integerStream1 = Stream.of(arr);
    }

    // 单列集合转换成Stream流
    private static void test01() {
        List<Author> authors = getAuthors();
        System.out.println(authors);

        authors.stream().
                distinct().
                filter(author -> author.getAge() < 18).
                forEach(author -> System.out.println(author.getName()));
    }

    private static List<Author> getAuthors() {
        // 数据初始化
        Author author = new Author(1L, "蒙多", 33, "一个从菜刀中明悟真理的祖安人", null);
        Author author2 = new Author(2L, "亚拉索", 15, "狂风也追不上他的思考速度", null);
        Author author3 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);
        Author author4 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);

        // 书籍列表
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L, "刀的两侧是光明与黑暗", "哲学，爱情", 88, "用一把刀划分了爱恨"));
        books1.add(new Book(2L, "一个人不能死在同一把刀下", "个人成长，爱情", 99, "讲述如何从失败中明悟真理"));

        books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
        books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
        books2.add(new Book(4L, "吹或不吹", "爱情，个人传记", 56, "一个哲学家的恋爱观注定很难被他所在的时代理解"));

        books3.add(new Book(5L, "你的剑就是我的剑", "爱情", 56, "无法想象，一个武者能对他的伴侣这么的宽容"));
        books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));
        books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));

        author.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> authorList = new ArrayList<>(Arrays.asList(author, author2, author3, author4));
        return authorList;
    }
}
